﻿namespace Dropthings.Test.Rules
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    using Microsoft.VisualStudio.TestTools.WebTesting;

    public class UpdatePanelExtracationData
    {
        public string UpdatePanelName { get; set; }
        public int UpdatePanelPositionInHtml { get; set; }
    }
    /// <summary>
    /// Extracts all the update panels in the output of an aspx page. It only supports visit or postback, it does not support scanning
    /// the output of Async Postback. Something to do.
    /// The update panels are added as: 
    /// $UPDATEPANEL.WidgetBodyUpdatePanel.1        = tWidgetPage$WidgetZone2407$WidgetContainer3930$WidgetBodyUpdatePanel	
    /// $UPDATEPANEL.WidgetBodyUpdatePanel.1.$POS   = 94788	(Position in the HTML)
    /// It also adds all the UpdatePanels in a sequence:
    /// $UPDATEPANEL.1	        = tUserTabPage$TabUpdatePanel	
    /// $UPDATEPANEL.1.$POS	    = 94789	
    /// </summary>
    public class ExtractUpdatePanels : ExtractionRule
    {
        #region Fields


        public static string UPDATE_PANEL_PREFIX = "$UPDATEPANEL.";
        public static string UPDATEPANEL_EXTRACTED_KEY = UPDATE_PANEL_PREFIX + "EXTRACTED";
        public static string UPDATE_PANEL_COUNT_KEY = UPDATE_PANEL_PREFIX + "COUNT";
        public static string UPDATE_PANEL_DECLARATION = "Sys.WebForms.PageRequestManager.getInstance()._updateControls([";
        public static string UPDATE_PANEL_POS_KEY = "$POS";


        public ExtractUpdatePanels()
        {

        }

        private static Regex _FindUpdatePanelRegex = new Regex(
            @"\|updatePanel\|(?<name>(.*?))\|",
            RegexOptions.IgnoreCase
            | RegexOptions.Multiline
            | RegexOptions.IgnorePatternWhitespace
            | RegexOptions.Compiled
            );

        #endregion Fields

        #region Methods

        public static void ExtractUpdatePanelNamesFromHtml(string body, WebTestContext context)
        {
            RuleHelper.NotAlreadyDone(context, UPDATEPANEL_EXTRACTED_KEY, () =>
                {
                    List<UpdatePanelExtracationData> list = ExtractUpdatePanelNamesFromHtml(body);
                    foreach (var item in list)
                    {
                        string idSelector = RuleHelper.PlaceIDSelector(context, item.UpdatePanelName);
                        string indexSelector = RuleHelper.PlaceIndexSelector(context, ControlCategory.UPDATEPANEL, item.UpdatePanelName);

                        context[idSelector + UPDATE_PANEL_POS_KEY] = item.UpdatePanelPositionInHtml;
                        context[indexSelector + UPDATE_PANEL_POS_KEY] = item.UpdatePanelPositionInHtml;


                    }
                    context[UPDATE_PANEL_COUNT_KEY] = list.Count;
                });
        }
        public static List<UpdatePanelExtracationData> ExtractUpdatePanelNamesFromHtml(string body)
        {
            List<UpdatePanelExtracationData> list = new List<UpdatePanelExtracationData>();

            // Do not extract update panel names twice
            int pos = body.IndexOf(UPDATE_PANEL_DECLARATION);
            if (pos > 0)
            {
                // found declaration of all update panels on the page
                pos += UPDATE_PANEL_DECLARATION.Length;
                int endPos = body.IndexOf(']', pos);
                string updatePanelNamesDelimited = body.Substring(pos, endPos - pos);
                string[] updatePanelNames = updatePanelNamesDelimited.Split(',');
                int updatePanelCounter = 0;
                foreach (string updatePanelName in updatePanelNames)
                {
                    // Create a unique key in the context using the UpdatePanel's Last part of the ID which is usually the
                    // ID specified in aspx page
                    string updatePanelFullId = updatePanelName.TrimStart('\'').TrimEnd('\'').TrimStart('t');
                    string updatePanelDivId = updatePanelFullId.Replace('$', '_');
                    // Look for a div with id having the updatepanel ID, e.g. <div id="UserTabPage_TabUpdatePanel">
                    string lookingFor = "<div id=\"" + updatePanelDivId + "\"";
                    // Find the position of the UpdatePanel
                    int updatePanelDivIdPos = body.IndexOf(lookingFor);

                    list.Add(new UpdatePanelExtracationData()
                    {
                        UpdatePanelName = updatePanelFullId,
                        UpdatePanelPositionInHtml = updatePanelDivIdPos
                    });




                    updatePanelCounter++;
                }
            }
            return list;
        }

        public override void Extract(object sender, ExtractionEventArgs e)
        {
            string body = e.Response.BodyString;
            if (IsHtmlResponse(e.Response))
                ExtractUpdatePanelNamesFromHtml(body, e.WebTest.Context);
            //else // if (e.Response.ContentType.Contains("text/plain"))
            //    ExtractUpdatePanelNamesFromAsyncPostback(body, e.WebTest.Context);
        }

        public static bool IsHtmlResponse(WebTestResponse response)
        {
            return response.ContentType.Contains("text/html");
        }

        private void ExtractUpdatePanelNamesFromAsyncPostback(string body, WebTestContext context)
        {

            RuleHelper.NotAlreadyDone(context, "$UPDATEPANEL.EXTRACTED", () =>
                {
                    int countOfKeys = context.Count;
                    int newUpdatePanelsAdded = 0;

                    var list = ExtractUpdatePanelNamesFromAsyncPostback(body);
                    foreach (var item in list)
                    {

                        RuleHelper.PlaceIDSelector(context, item.UpdatePanelName);
                        RuleHelper.PlaceIndexSelector(context, ControlCategory.UPDATEPANEL, item.UpdatePanelName);

                        if (context.Count > countOfKeys)
                            newUpdatePanelsAdded++;
                    }
                    context[UPDATE_PANEL_COUNT_KEY] = ((int)context[UPDATE_PANEL_COUNT_KEY]) + newUpdatePanelsAdded;
                });
        }

        public static List<UpdatePanelExtracationData> ExtractUpdatePanelNamesFromAsyncPostback(string body)
        {
            List<UpdatePanelExtracationData> list = new List<UpdatePanelExtracationData>();

            foreach (Match match in _FindUpdatePanelRegex.Matches(body))
            {
                string updatePanelDivID = match.Groups["name"].Value;
                string updatePanelFullId = updatePanelDivID;//.Replace('_', '$');
                list.Add(new UpdatePanelExtracationData()
                {
                    UpdatePanelName = updatePanelFullId
                });

            }
            return list;
        }

        #endregion Methods
    }
}